
{***********************************************************}
{                                                           }
{      Informix Data Access Components                      }
{                                                           }
{      Data Type Convertions                                }
{                                                           }
{      Copyright (c) 2001-2008 Luxena Software Company      }
{      http://www.luxena.com                                }
{      e-mail: support@luxena.com                           }
{                                                           }
{***********************************************************}

unit IfxConvert;

{$I lx.inc}

interface

uses
  LXDBTypes, IfxTypes, IfxDecimal, IfxDateTime, IfxInt8;

  
{ Locale Specific Information }
function InformixDecimalSeparator: Char;

{ Numeric conversions }
function SmallIntToDecimal(Source: int2): TDecimal;
function SmallIntToInt8(Source: int2): TIfx_int8;
function StringToSmallInt(const Source: string): int2;

function IntToStringFmt(Source: int4; const Format: string): string;
function IntToDecimal(Source: int4): TDecimal;
function IntToInt8(Source: int4): TIfx_int8;
function StringToInt(const Source: string): int4;

function FloatToString(Source: Double): string;
function FloatToStringFmt(Source: Double; const Format: string): string;
function FloatToDecimal(Source: Double): TDecimal;
function FloatToInt8(Source: Double): TIfx_int8;
function SmallFloatToInt8(Source: Single): TIfx_int8;
function StringToFloat(const Source: string): Double;

function DecimalToString(const Source: TDecimal): string;
function DecimalToStringFmt(const Source: TDecimal; const Format: string): string;
function DecimalToSmallInt(const Source: TDecimal): int2;
function DecimalToInt(const Source: TDecimal): int4;
function DecimalToFloat(const Source: TDecimal): Double;
function DecimalToCurrency(const Source: TDecimal): Currency;
function DecimalToBcd(const Source: TDecimal; ColPrec: Integer = 0;
  ColScale: Integer = 0): TBcd;
function DecimalToInt64(const Source: TDecimal): Int64;
function DecimalToVariant(const Source: TDecimal): Variant;
function DecimalToInt8(const Source: TDecimal): TIfx_int8;
function StringToDecimal(const Source: string): TDecimal;
function CurrencyToDecimal(Source: Currency): TDecimal;
function BcdToDecimal(const Source: TBcd): TDecimal;
function Int64ToDecimal(Source: Int64): TDecimal;
function VariantToDecimal(const Source: Variant): TDecimal;
function DecimalAdd(const Left, Right: TDecimal): TDecimal;
function DecimalCmp(const Left, Right: TDecimal): Integer;
function DecimalDiv(const Left, Right: TDecimal): TDecimal;
function DecimalMul(const Left, Right: TDecimal): TDecimal;
procedure DecimalRound(var Value: TDecimal; Scale: mint);
function DecimalSub(const Left, Right: TDecimal): TDecimal;
procedure DecimalTrunc(var Value: TDecimal; Scale: mint);

function Int8ToString(const Source: TIfx_int8): string;
function Int8ToSmallInt(const Source: TIfx_int8): int2;
function Int8ToInt(const Source: TIfx_int8): int4;
function Int8ToFloat(const Source: TIfx_int8): Double;
function Int8ToSmallFloat(const Source: TIfx_int8): Single;
function Int8ToBcd(const Source: TIfx_int8): TBcd;
function Int8ToInt64(const Source: TIfx_int8): Int64;
function Int8ToDecimal(const Source: TIfx_int8): TDecimal;
function StringToInt8(const Source: string): TIfx_int8;
function CurrencyToInt8(Source: Currency): TIfx_int8;
function BcdToInt8(const Source: TBcd): TIfx_int8;
function Int64ToInt8(Source: Int64): TIfx_int8;
function Int8Cmp(const Left, Right: TIfx_int8): Integer;
function Int8Sub(const Left, Right: TIfx_int8): TIfx_int8;
function Int8Add(const Left, Right: TIfx_int8): TIfx_int8;
function Int8Mul(const Left, Right: TIfx_int8): TIfx_int8;
function Int8Div(const Left, Right: TIfx_int8): TIfx_int8;

{ Datetime conversions }
const
  IFX_DATE_DELTA = 693595; { since 0001-01-01 in Delphi to 1899-12-31 in Informix }

function DateToString(Source: int4): string;
function DateToStringFmt(Source: int4; const Format: string): string;
function DateToDateTime(Source: int4): TDateTime;
function DateToTimeStamp(Source: int4): TSQLTimeStamp;
function DateToDTime(Source: int4): TDTime;
function StringToDate(const Source: string): int4;
function DateTimeToDate(Source: TDateTime): int4;
function TimeStampToDate(const Source: TSQLTimeStamp): int4;
function DTimeToDate(const Source: TDTime): int4;

function DTimeToString(const Source: TDTime): string;
function DTimeToStringFmt(const Source: TDTime; const Format: string): string;
function DTimeToTime(const Source: TDTime): TDateTime;
function DTimeToDateTime(const Source: TDTime): TDateTime;
function DTimeToTimeStamp(const Source: TDTime): TSQLTimeStamp;
function StringToDTime(const Source: string; Qual: int2): TDTime;
function TimeToDTime(Source: TDateTime): TDTime;
function DateTimeToDTime(Source: TDateTime): TDTime;
function TimeStampToDTime(const Source: TSQLTimeStamp): TDTime;
function DTimeAddInterval(const Left: TDTime; const Right: TIntrvl): TDTime;
function DTimeCurrent(Qual: int2 = 0): TDTime;
function DTimeExtend(const Source: TDTime; Qual: int2 = 0): TDTime;
function DTimeSub(const Left, Right: TDTime; Qual: int2 = 0): TIntrvl;
function DTimeSubInterval(const Left: TDTime; const Right: TIntrvl): TDTime;

function IntervalToString(const Source: TIntrvl): string;
function IntervalToStringFmt(const Source: TIntrvl; const Format: string): string;
function StringToInterval(const Source: string; Qual: int2): TIntrvl;
function IntervalDivDouble(const Left: TIntrvl; const Right: Double; Qual: int2 = 0): TIntrvl;
function IntervalDiv(const Left, Right: TIntrvl): Double;
function IntervalExtend(const Source: TIntrvl; Qual: int2 = 0): TIntrvl;
function IntervalMulDouble(const Left: TIntrvl; const Right: Double; Qual: int2 = 0): TIntrvl;


implementation

uses SysUtils, LXTypes, Ifx, IfxIntf;


{ Locale Specific Information }

function InformixDecimalSeparator: Char;
var
  Buffer: array [0..1] of Char;
begin
  CheckInformixResult(rfmtdouble(0, '.', Buffer));
  Result := Buffer[0];
end;


{ Numeric conversions }

function SmallIntToDecimal(Source: int2): TDecimal;
begin
  CheckInformixResult(deccvint(Source, @Result));
end;

function SmallIntToInt8(Source: int2): TIfx_int8;
begin
  CheckInformixResult(ifx_int8cvint(Source, @Result));
end;

function StringToSmallInt(const Source: string): int2;
begin
  CheckInformixResult(rstoi(PChar(Source), @Result));
end;

function IntToStringFmt(Source: int4; const Format: string): string;
begin
  SetString(Result, nil, Length(Format) + 1);
  CheckInformixResult(rfmtlong(Source, PChar(Format), PChar(Result)));
  SetLength(Result, StrLen(PChar(Result)));
end;

function IntToDecimal(Source: int4): TDecimal;
begin
  CheckInformixResult(deccvlong(Source, @Result));
end;

function IntToInt8(Source: int4): TIfx_int8;
begin
  CheckInformixResult(ifx_int8cvlong(Source, @Result));
end;

function StringToInt(const Source: string): int4;
begin
  CheckInformixResult(rstol(PChar(Source), @Result));
end;

function FloatToDecimal(Source: Double): TDecimal;
begin
  CheckInformixResult(deccvdbl(Source, @Result));
end;

function FloatToInt8(Source: Double): TIfx_int8;
begin
  CheckInformixResult(ifx_int8cvdbl(Source, @Result));
end;

function SmallFloatToInt8(Source: Single): TIfx_int8;
begin
  CheckInformixResult(ifx_int8cvflt(Source, @Result));
end;

function FloatToString(Source: Double): string;
var
  DecimalPos: Integer;
begin
  Result := FloatToStr(Source);
  if SysUtils.DecimalSeparator <> InformixDecimalSeparator then
  begin
    DecimalPos := Pos(SysUtils.DecimalSeparator, Result);
    if DecimalPos > 0 then
      Result[DecimalPos] := InformixDecimalSeparator;
  end;
end;

function FloatToStringFmt(Source: Double; const Format: string): string;
begin
  SetString(Result, nil, Length(Format) + 1);
  CheckInformixResult(rfmtdouble(Source, PChar(Format), PChar(Result)));
  SetLength(Result, StrLen(PChar(Result)));
end;

function StringToFloat(const Source: string): Double;
begin
  CheckInformixResult(rstod(PChar(Source), @Result));
end;

function DecimalToString(const Source: TDecimal): string;
var
  Buffer: array [0..127] of Char;
begin
  dectoasc(@Source, Buffer, SizeOf(Buffer) - 1, -1);
  Result := TrimRight(Buffer);
end;

function DecimalToStringFmt(const Source: TDecimal; const Format: string): string;
begin
  SetString(Result, nil, Length(Format) + 1);
  CheckInformixResult(rfmtdec(@Source, PChar(Format), PChar(Result)));
  SetLength(Result, StrLen(PChar(Result)));
  Result := Trim(Result);
end;

function DecimalToSmallInt(const Source: TDecimal): int2;
begin
  CheckInformixResult(dectoint(@Source, @Result));
end;

function DecimalToInt(const Source: TDecimal): int4;
begin
  CheckInformixResult(dectolong(@Source, @Result));
end;

function DecimalToFloat(const Source: TDecimal): Double;
var
  Base: Double;
  Digit: PByte;
  I: Integer;
begin
  Result := 0;
  if Source.dec_ndgts = 0 then Exit;

  Base := 0.01;
  if Source.dec_exp > 0 then
    for I := 1 to Source.dec_exp do
      Base := Base*100.0
  else if Source.dec_exp < 0 then
    for I := -1 downto Source.dec_exp do
      Base := Base/100.0;

  Digit := @Source.dec_dgts;
  for I := 0 to Source.dec_ndgts - 1 do
  begin
    Result := Result + Digit^*Base;
    Base := Base/100;
    Inc(Digit);
  end;
  
  if Source.dec_pos = 0 then
    Result := -1*Result;
end;

function DecimalToCurrency(const Source: TDecimal): Currency;
var
  Base: Currency;
  Digit: PByte;
  I: Integer;
begin
  Result := 0;
  if Source.dec_ndgts = 0 then Exit;

  Base := 0.01;
  if Source.dec_exp > 0 then
    for I := 1 to Source.dec_exp do
      Base := Base*100.0
  else if Source.dec_exp < 0 then
    for I := -1 downto Source.dec_exp do
      Base := Base/100.0;

  Digit := @Source.dec_dgts;
  for I := 0 to Source.dec_ndgts - 1 do
  begin
    Result := Result + Digit^*Base;
    Base := Base/100;
    Inc(Digit);
  end;
  if Source.dec_pos = 0 then
    Result := -1*Result;
end;

function DecimalToBcd(const Source: TDecimal; ColPrec: Integer = 0;
  ColScale: Integer = 0): TBcd;
var
  pNibble: PByte;
  pDigit: PByte;
  chDigit, chDigitHigh, chDigitLow: Byte;
  I: Integer;
  cLeadZeros: Integer;
begin
  { clear destinition value }
  FillChar(Result, SizeOf(TBcd), 0);

  { if no signicant digits nothing to convert }
  if Source.dec_ndgts = 0 then
  begin
    Result.Precision := 1; { 1 - the minimal value to avoid exception in BcdToCurr }
    Exit;
  end;

  pNibble := @Result.Fraction;

  { evaluate bcd precision and scale of decimal }
  if Source.dec_exp < 0 then
  begin
    cLeadZeros := -Source.dec_exp;
    if cLeadZeros >= SizeOf(Result.Fraction) then
    begin
      Result.Precision := 1;
      Exit;
    end;
    Result.Precision := Source.dec_ndgts + cLeadZeros;
    if Result.Precision >= SizeOf(Result.Fraction) then
    begin
      decround(@Source, 2*(SizeOf(Result.Fraction) - 1));
      Result := DecimalToBcd(Source, ColPrec, ColScale);
      Exit;
    end;
    Result.Precision := 2*Result.Precision;
    Result.SignSpecialPlaces := Result.Precision;
    Inc(pNibble, cLeadZeros);
  end else
    if Source.dec_exp < Source.dec_ndgts then
    begin
      Result.Precision := 2*Source.dec_ndgts;
      Result.SignSpecialPlaces := 2*(Source.dec_ndgts - Source.dec_exp);
    end else
    begin
      Result.Precision := 2*Source.dec_exp;
      Result.SignSpecialPlaces := 0;
    end;

  { convert decimal digits into bcd nibbles }
  pDigit := @Source.dec_dgts;
  chDigit := pDigit^;
  chDigitHigh := chDigit div 10;
  if (chDigitHigh = 0) and ((ColPrec - ColScale) and 1 <> 0) and
    (Result.SignSpecialPlaces < Result.Precision) then
  begin
    for I := 1 to Source.dec_ndgts - 1 do
    begin
      pNibble^ := (chDigit mod 10) shl 4;
      Inc(pDigit);
      chDigit := pDigit^;
      pNibble^ := pNibble^ or (chDigit div 10);
      Inc(pNibble);
    end;
    chDigitLow := (chDigit mod 10) shl 4;
    pNibble^ := chDigitLow;
    Dec(Result.Precision);
  end else
  begin
    chDigitLow := chDigit mod 10;
    pNibble^ := (chDigitHigh shl 4) or chDigitLow;
    Inc(pNibble);
    for I := 1 to Source.dec_ndgts - 1 do
    begin
      Inc(pDigit);
      chDigit := pDigit^;
      chDigitLow := chDigit mod 10;
      pNibble^ := ((chDigit div 10) shl 4) or chDigitLow;
      Inc(pNibble);
    end;
  end;

  if (chDigitLow = 0) and (Result.SignSpecialPlaces > 0) then
  begin
    Dec(Result.Precision);
    Dec(Result.SignSpecialPlaces);
  end;

  { set precision, sign bit, null bit and fraction count }
  if Source.dec_pos = 0 then
    Result.SignSpecialPlaces := Result.SignSpecialPlaces or $80;
  if Source.dec_pos = -1 then
    Result.SignSpecialPlaces := Result.SignSpecialPlaces or $40;
end;

function DecimalToInt64(const Source: TDecimal): Int64;
begin
  Result := Int8ToInt64(DecimalToInt8(Source));
end;

{$IFDEF D6}
function DecimalToVariant(const Source: TDecimal): Variant;
begin
  Result := LXBcdToVar(DecimalToBcd(Source));
end;
{$ELSE}
function DecimalToVariant(const Source: TDecimal): Variant;
begin
  Result := DecimalToCurrency(Source);
end;
{$ENDIF}

function DecimalToInt8(const Source: TDecimal): TIfx_int8;
begin
  CheckInformixResult(ifx_int8cvdec(@Source, @Result));
end;

function StringToDecimal(const Source: string): TDecimal;
begin
  CheckInformixResult(deccvasc(PChar(Source), Length(Source), @Result));
end;

function CurrencyToDecimal(Source: Currency): TDecimal;
var
  Bcd: TBcd;
begin
  if LXCurrToBcd(Source, Bcd) then
    Result := BcdToDecimal(Bcd) else
    FillChar(Result, SizeOf(Result), 0);
end;

function BcdToDecimal(const Source: TBcd): TDecimal;
var
  Precision: Integer;
  PrecisionIsOdd: Boolean;
  SignSpecialPlaces: Integer;
  NonZero: Integer;
  Nibble: Byte;

  pNibble: PByte;
  pDigit: PByte;

  dec_exp: Integer;
  dec_ndgts: Integer;

  I: Integer;
begin
  Precision := Source.Precision;

  { if precision is 0 then value is 0 }
  if Precision = 0 then
  begin
    Result.dec_ndgts := 0;
    Exit;
  end;

  { analyze is bcd precision odd number }
  PrecisionIsOdd := Precision and $01 <> 0;

  { set decimal sign }
  SignSpecialPlaces := Source.SignSpecialPlaces;
  if SignSpecialPlaces and $40 <> 0 then
    Result.dec_pos := -1 else
    Result.dec_pos := (SignSpecialPlaces xor $80) shr 7;

  { find first non zero byte }
  NonZero := 0;
  pNibble := @Source.Fraction;
  while pNibble^ = 0 do
  begin
    Inc(NonZero);
    Inc(pNibble);
  end;

  { evaluate 10 based exponent of decimal }
  SignSpecialPlaces := SignSpecialPlaces and $3F;
  dec_exp := Precision - SignSpecialPlaces;

  { convert bcd nibbles into decimal digits, count number of significant
    digits and evaluate 100 based decimal exponent }
  pDigit := @Result.dec_dgts;
  if dec_exp and $01 <> 0 then
  begin
    { in this case it is needed to shift digits for one position to right }
    if pNibble^ and $F0 <> 0 then
    begin
      pDigit^ := pNibble^ shr 4;
      Inc(pDigit^);
      Inc(dec_exp);
      dec_ndgts := 1;
    end else
      dec_ndgts := 0;

    Dec(Precision);
    Precision := Precision shr 1;

    for I := NonZero to Precision - 1 do
    begin
      Nibble := pNibble^;
      Inc(pNibble);
      pDigit^ := (Nibble and $0F)*10 + (pNibble^ shr 4);
      Inc(pDigit);
      Inc(dec_ndgts);
    end;

    if not PrecisionIsOdd then
    begin
      pDigit^ := (pNibble^ and $0F)*10;
      Inc(dec_ndgts);
    end;
  end else
  begin
    Precision := Precision shr 1;
    dec_ndgts := 0;

    for I := NonZero to Precision - 1 do
    begin
      pDigit^ := (pNibble^ shr 4)*10 + (pNibble^ and $0F);
      Inc(pDigit);
      Inc(pNibble);
      Inc(dec_ndgts);
    end;

    if PrecisionIsOdd then
    begin
      pDigit^ := (pNibble^ shr 4)*10;
      Inc(dec_ndgts);
    end;
  end;

  { set decimal exponent }
  Result.dec_exp := (dec_exp shr 1) - NonZero;

  { set decimal significant digits number }
  Result.dec_ndgts := dec_ndgts;
end;

function Int64ToDecimal(Source: Int64): TDecimal;
begin
  Result := Int8ToDecimal(Int64ToInt8(Source));
end;

function VariantToDecimal(const Source: Variant): TDecimal;
begin
  Result := BcdToDecimal(LXVarToBcd(Source));
end;

function DecimalAdd(const Left, Right: TDecimal): TDecimal;
begin
  CheckInformixResult(decadd(@Left, @Right, @Result));
end;

function DecimalCmp(const Left, Right: TDecimal): Integer;
begin
  Result := deccmp(@Left, @Right);
end;

function DecimalDiv(const Left, Right: TDecimal): TDecimal;
begin
  CheckInformixResult(decdiv(@Left, @Right, @Result));
end;

function DecimalMul(const Left, Right: TDecimal): TDecimal;
begin
  CheckInformixResult(decmul(@Left, @Right, @Result));
end;

procedure DecimalRound(var Value: TDecimal; Scale: mint);
begin
  decround(@Value, Scale);
end;

function DecimalSub(const Left, Right: TDecimal): TDecimal;
begin
  CheckInformixResult(decsub(@Left, @Right, @Result));
end;

procedure DecimalTrunc(var Value: TDecimal; Scale: mint);
begin
  dectrunc(@Value, Scale);
end;

function Int8ToString(const Source: TIfx_int8): string;
var
  Buffer: array [0..21] of Char;
begin
  CheckInformixResult(ifx_int8toasc(@Source, Buffer, SizeOf(Buffer) - 1));
  Result := TrimRight(Buffer);
end;

function Int8ToSmallInt(const Source: TIfx_int8): int2;
begin
  CheckInformixResult(ifx_int8toint(@Source, @Result));
end;

function Int8ToInt(const Source: TIfx_int8): int4;
begin
  CheckInformixResult(ifx_int8tolong(@Source, @Result));
end;

function Int8ToFloat(const Source: TIfx_int8): Double;
begin
  CheckInformixResult(ifx_int8todbl(@Source, @Result));
end;

function Int8ToSmallFloat(const Source: TIfx_int8): Single;
begin
  CheckInformixResult(ifx_int8toflt(@Source, @Result));
end;

function Int8ToBcd(const Source: TIfx_int8): TBcd;
begin
  Result := DecimalToBcd(Int8ToDecimal(Source));
end;

function Int8ToInt64(const Source: TIfx_int8): Int64;
begin
  with Source do
    if sign = 0 then
      Result := 0 else
    begin
      Result := PInt64(@data)^;
      if sign < 0 then
        Result := -Result;
    end;
end;

function Int8ToDecimal(const Source: TIfx_int8): TDecimal;
begin
  CheckInformixResult(ifx_int8todec(@Source, @Result));
end;

function StringToInt8(const Source: string): TIfx_int8;
begin
  CheckInformixResult(ifx_int8cvasc(PChar(Source), Length(Source), @Result));
end;

function CurrencyToInt8(Source: Currency): TIfx_int8;
begin
  Result := Int64ToInt8(Round(Source));
end;

function BcdToInt8(const Source: TBcd): TIfx_int8;
begin
  Result := DecimalToInt8(BcdToDecimal(Source));
end;

function Int64ToInt8(Source: Int64): TIfx_int8;
begin
  with Result do
    if Source >= 0 then
    begin
      sign := 1;
      PInt64(@data)^ := Source;
    end else
    begin
      sign := -1;
      PInt64(@data)^ := -Source;
    end;
end;

function Int8Cmp(const Left, Right: TIfx_int8): Integer;
begin
  Result := ifx_int8cmp(@Left, @Right);
end;

function Int8Sub(const Left, Right: TIfx_int8): TIfx_int8;
begin
  CheckInformixResult(ifx_int8sub(@Left, @Right, @Result));
end;

function Int8Add(const Left, Right: TIfx_int8): TIfx_int8;
begin
  CheckInformixResult(ifx_int8add(@Left, @Right, @Result));
end;

function Int8Mul(const Left, Right: TIfx_int8): TIfx_int8;
begin
  CheckInformixResult(ifx_int8mul(@Left, @Right, @Result));
end;

function Int8Div(const Left, Right: TIfx_int8): TIfx_int8;
begin
  CheckInformixResult(ifx_int8div(@Left, @Right, @Result));
end;


{ Datetime conversions }

const
  DateDelta = 1; { days between 1899-12-31 and 1900-01-01 }
  
function DateToString(Source: int4): string;
var
  Buffer: array [0..127] of Char;
begin
  CheckInformixResult(rdatestr(Source, Buffer));
  Result := Buffer;
end;

function DateToStringFmt(Source: int4; const Format: string): string;
begin
  SetString(Result, nil, Length(Format) + 1);
  CheckInformixResult(rfmtdate(Source, PChar(Format), PChar(Result)));
  SetLength(Result, StrLen(PChar(Result)));
end;

function DateToDateTime(Source: int4): TDateTime;
begin
  Result := Source + DateDelta;
end;

function DateToTimeStamp(Source: int4): TSQLTimeStamp;
var
  mdy: array [0..2] of int2;
begin
  CheckInformixResult(rjulmdy(Source, @mdy));
  Result.Year := mdy[2];
  Result.Month := mdy[0];
  Result.Day := mdy[1];
  Result.Hour := 0;
  Result.Minute := 0;
  Result.Second := 0;
  Result.Fractions := 0;
end;

function DateToDTime(Source: int4): TDTime;
var
  mdy: array [0..2] of int2;
  Digit: PByte;
begin
  CheckInformixResult(rjulmdy(Source, @mdy));
  Result.dt_qual := TU_ENCODE(8, TU_YEAR, TU_DAY);
  with Result.dt_dec do
  begin
    dec_exp := 7;
    dec_pos := 1;
    dec_ndgts := 4;
    Digit := @dec_dgts[0];
  end;
  Digit^ := mdy[2] div 100;
  Inc(Digit);
  Digit^ := mdy[2] mod 100;
  Inc(Digit);
  Digit^ := mdy[0];
  Inc(Digit);
  Digit^ := mdy[1];
end;

function StringToDate(const Source: string): int4;
begin
  CheckInformixResult(rstrdate(PChar(Source), @Result));
end;

function DateTimeToDate(Source: TDateTime): int4;
begin
  Result := Trunc(Source) - DateDelta;
end;

function TimeStampToDate(const Source: TSQLTimeStamp): int4;
var
  mdy: array [0..2] of int2;
begin
  mdy[2] := Source.Year;
  mdy[0] := Source.Month;
  mdy[1] := Source.Day;
  CheckInformixResult(rmdyjul(@mdy, @Result));
end;

function DTimeToDate(const Source: TDTime): int4;
begin
  Result := TimeStampToDate(DTimeToTimeStamp(Source));
end;

function DTimeToString(const Source: TDTime): string;
var
  Buffer: array [0..127] of Char;
begin
  CheckInformixResult(dttoasc(@Source, Buffer));
  Result := Buffer;
end;

function DTimeToStringFmt(const Source: TDTime; const Format: string): string;
var
  Buffer: array [0..127] of Char;
begin
  CheckInformixResult(dttofmtasc(@Source, Buffer, SizeOf(Buffer) - 1, PChar(Format)));
  Result := Buffer;
end;

function DTimeToTime(const Source: TDTime): TDateTime;
begin
  with DTimeToTimeStamp(Source)do
    Result := EncodeTime(Hour, Minute, Second, Fractions);
end;

function DTimeToDateTime(const Source: TDTime): TDateTime;
var
  D, T: TDateTime;
begin
  with DTimeToTimeStamp(Source) do
  begin
    D := EncodeDate(Year, Month, Day);
    T := EncodeTime(Hour, Minute, Second, Fractions);
  end;
  if D < 0 then
    Result := D - T else
    Result := D + T;
end;

function DTimeToTimeStamp(const Source: TDTime): TSQLTimeStamp;
var
  TmpValue: TDTime;

  pdec: PDecimal;
  ndgts: Integer;
  dgt_pos: Integer;
  tu_pos: Integer;
  pdgt: PByte;
  pfld: PWord;

  function CheckDigit: Boolean;
  begin
    Inc(dgt_pos);
    Result := dgt_pos >= ndgts;
  end;

begin
  FillChar(Result, SizeOf(Result), 0);

  TmpValue.dt_qual := TU_CURRQUAL;
  if Source.dt_qual = TmpValue.dt_qual then
    pdec := @Source.dt_dec else
  begin
    dtextend(@Source, @TmpValue);
    pdec := @TmpValue.dt_dec;
  end;

  ndgts := pdec.dec_ndgts;

  { if no signicant digits nothing to convert }
  if ndgts = 0 then Exit;

  dgt_pos := 0;
  pdgt := @pdec.dec_dgts;

  tu_pos := TU_FRAC - (pdec.dec_exp shl 1);
  if tu_pos <= 0 then
  begin
    tu_pos := tu_pos div 2;
    Inc(tu_pos);
  end;
  pfld := @Result;

  { set year }
  if tu_pos < TU_MONTH then
  begin
    if tu_pos = TU_YEAR then
    begin
      pfld^ := pdgt^*100;
      Inc(pdgt);
      if CheckDigit then Exit;
      Inc(tu_pos);
      Inc(pfld^, pdgt^);
    end else
      pfld^ := pdgt^;
    Inc(pdgt);
    Inc(pfld);
    if CheckDigit then Exit;
    Inc(tu_pos);
  end else
    pfld := @(PChar(pfld)[tu_pos]);

  { set month, day, hour, minute and second }
  while tu_pos < TU_FRAC do
  begin
    pfld^ := pdgt^;
    Inc(pdgt);
    Inc(pfld);
    if CheckDigit then Exit;
    Inc(tu_pos, 2);
  end;

  { set fraction }
  PWord(pfld)^ := pdgt^ * 10;
  if CheckDigit then Exit;
  Inc(pdgt);
  Inc(PWord(pfld)^, pdgt^ div 10);
end;

function StringToDTime(const Source: string; Qual: int2): TDTime;
begin
  Result.dt_qual := Qual;
  CheckInformixResult(dtcvasc(PChar(Source), @Result));
end;

function TimeToDTime(Source: TDateTime): TDTime;
var
  Hour, Min, Sec, MSec: Word;
  Digit: PByte;
begin
  DecodeTime(Source, Hour, Min, Sec, MSec);
  Result.dt_qual := TU_ENCODE(9, TU_HOUR, TU_F3);
  with Result.dt_dec do
  begin
    dec_exp := 3;
    dec_pos := 1;
    dec_ndgts := 4;
    Digit := @dec_dgts[0];
  end;
  Digit^ := Hour;
  Inc(Digit);
  Digit^ := Min;
  Inc(Digit);
  Digit^ := Sec;
  Inc(Digit);
  Digit^ := MSec div 10;
  Inc(Digit);
  Digit^ := (MSec mod 10) * 10;
end;

function DateTimeToDTime(Source: TDateTime): TDTime;
var
  TimeStamp: TSQLTimeStamp;
  MSec: Word;
begin
  DecodeDate(Source, Word(TimeStamp.Year), TimeStamp.Month, TimeStamp.Day);
  DecodeTime(Source, TimeStamp.Hour, TimeStamp.Minute, TimeStamp.Second, MSec);
  TimeStamp.Fractions := MSec;
  Result := TimeStampToDTime(TimeStamp);
end;

function TimeStampToDTime(const Source: TSQLTimeStamp): TDTime;
var
  Digit: PByte;
begin
  Result.dt_qual := TU_CURRQUAL;
  with Result.dt_dec do
  begin
    dec_exp := 7;
    dec_pos := 1;
    dec_ndgts := 9;
    Digit := @dec_dgts;
  end;
  Digit^ := Source.Year div 100;
  Inc(Digit);
  Digit^ := Source.Year mod 100;
  Inc(Digit);
  Digit^ := Source.Month;
  Inc(Digit);
  Digit^ := Source.Day;
  Inc(Digit);
  Digit^ := Source.Hour;
  Inc(Digit);
  Digit^ := Source.Minute;
  Inc(Digit);
  Digit^ := Source.Second;
  Inc(Digit);
  Digit^ := Source.Fractions div 10;
  Inc(Digit);
  Digit^ := (Source.Fractions mod 10) * 10;
end;

function DTimeAddInterval(const Left: TDTime; const Right: TIntrvl): TDTime;
begin
  CheckInformixResult(dtaddinv(@Left, @Right, @Result));
end;

function DTimeCurrent(Qual: int2): TDTime;
begin
  Result.dt_qual := Qual;
  dtcurrent(@Result);
end;

function DTimeExtend(const Source: TDTime; Qual: int2 = 0): TDTime;
begin
  if Qual = 0 then
    Result.dt_qual := Source.dt_qual else
    Result.dt_qual := Qual;
  CheckInformixResult(dtextend(@Source, @Result));
end;

function DTimeSub(const Left, Right: TDTime; Qual: int2): TIntrvl;
begin
  if Qual = 0 then
    Result.in_qual := Left.dt_qual else
    Result.in_qual := Qual;
  CheckInformixResult(dtsub(@Left, @Right, @Result));
end;

function DTimeSubInterval(const Left: TDTime; const Right: TIntrvl): TDTime;
begin
  CheckInformixResult(dtsubinv(@Left, @Right, @Result));
end;

function IntervalToString(const Source: TIntrvl): string;
var
  Buffer: array [0..127] of Char;
begin
  CheckInformixResult(intoasc(@Source, Buffer));
  Result := Buffer;
end;

function IntervalToStringFmt(const Source: TIntrvl; const Format: string): string;
var
  Buffer: array [0..127] of Char;
begin
  CheckInformixResult(intofmtasc(@Source, Buffer, SizeOf(Buffer) - 1, PChar(Format)));
  Result := Buffer;
end;

function StringToInterval(const Source: string; Qual: int2): TIntrvl;
begin
  Result.in_qual := Qual;
  CheckInformixResult(incvasc(PChar(Source), @Result));
end;

function IntervalDivDouble(const Left: TIntrvl; const Right: Double; Qual: int2): TIntrvl;
begin
  if Qual = 0 then
    Result.in_qual := Left.in_qual else
    Result.in_qual := Qual;
  CheckInformixResult(invdivdbl(@Left, Right, @Result));
end;

function IntervalDiv(const Left, Right: TIntrvl): Double;
begin
  CheckInformixResult(invdivinv(@Left, @Right, @Result));
end;

function IntervalExtend(const Source: TIntrvl; Qual: int2 = 0): TIntrvl;
begin
  if Qual = 0 then
    Result.in_qual := Source.in_qual else
    Result.in_qual := Qual;
  CheckInformixResult(invextend(@Source, @Result));
end;

function IntervalMulDouble(const Left: TIntrvl; const Right: Double; Qual: int2): TIntrvl;
begin
  if Qual = 0 then
    Result.in_qual := Left.in_qual else
    Result.in_qual := Qual;
  CheckInformixResult(invmuldbl(@Left, Right, @Result));
end;


end.